package net.peelmeagrape.hibernate.xmlgen;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.DOMWriter;
import org.hibernate.util.XMLHelper;

import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.IOException;
import java.util.*;

public class XmlUtils
{
    public static String loadAndNormaliseResource(String resourceName) throws DocumentException
    {
        Document document = loadResource(resourceName);
        return prettyPrint(document);
    }

    public static Document loadResource(String resourceName)
            throws DocumentException
    {
        InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
        SAXReader xmlReader = getSaxReader(true);
        return xmlReader.read(resourceAsStream);
    }

    private static SAXReader getSaxReader(boolean validating)
    {
        SAXReader xmlReader = new SAXReader();
        xmlReader.setMergeAdjacentText(validating);
        xmlReader.setValidation(validating);
        xmlReader.setEntityResolver(XMLHelper.DEFAULT_DTD_RESOLVER);
        return xmlReader;
    }

    public static String normaliseXml(String mappingXml) throws DocumentException
    {
        if(mappingXml==null)
            return null;
        return prettyPrint(getSaxReader(true).read(new StringReader(mappingXml)));
    }

    public static Document normaliseXml(Document mappingXml) throws DocumentException
    {
        return getSaxReader(true).read(new StringReader(mappingXml.asXML()));
    }

    public static String prettyPrint(Document doc)
    {
        if(doc==null) return null;
        try
        {
            OutputFormat outformat = OutputFormat.createPrettyPrint();
            StringWriter stringWriter = new StringWriter();
            XMLWriter writer = new XMLWriter(stringWriter, outformat);
            writer.write(doc);
            writer.flush();
            writer.close();
            return stringWriter.toString();
        }
        catch (IOException e)
        {
            throw new RuntimeException(e.getMessage(),e);
        }
    }

    public static Document parseXml(String wrappedXml)
            throws DocumentException
    {
        return getSaxReader(false).read(new StringReader(wrappedXml));
    }

    public static org.w3c.dom.Document toDom(Document expected) throws DocumentException
    {
        DOMWriter domWriter = new DOMWriter();
        return domWriter.write(expected);
    }

    public static void reorderChildElements(Element classElement, final String childorder)
    {
        if(classElement==null)
            return;
        List<Element> elements = classElement.elements();
        List<Element> copiedEls = new ArrayList<Element>(elements);
        Collections.sort(copiedEls, new Comparator<Element>() {
            public int compare(Element o1, Element o2)
            {
                String name1 = o1.getName();
                String name2 = o2.getName();
                int index1 = getIndex(name1);
                int index2 = getIndex(name2);
                if(index1==-1 && index2>=0)
                    return -1;
                if(index2==-1 && index1>=0)
                    return 1;
                if(index2==-1 && index1==-1)
                    return name1.compareTo(name2);
                if(index2==index1)
                    return name1.compareTo(name2);
                return index1-index2;
            }

            private int getIndex(String name)
            {
                return childorder.indexOf(name);
            }
        });
        for (Element element : copiedEls) {
            classElement.remove(element);
            classElement.add(element);
        }
    }
}
